<?php
require_once(dirname(__FILE__)."/../common/constants.php");
require_once(DB_SESSION_DIR_PATH."/db_operator.php");
require_once(DB_SESSION_DIR_PATH."/db_obj_defs.php");
require_once(COMMON_DIR_PATH."/session_controller.php");
require_once(TRANSACTIONS_DIR_PATH."/trans_common.php");

/*
 * Created on 2007-11-27
 * Author: William
 */
class UserManager extends User {
	/*
	 * Register a user.
	 */
	public function register() {
		/*
		 * Validate the user name provided.
		 */
		$bInUse = UserManager::is_user_name_in_use($this->name);
		if ($bInUse)
			return UsrRegStat::NAME_IN_USE;
		
		/*
		 * Get user information from parent class, then invoke database operator to create the user.
		 */
		$id = parent::register(CONFIGURATION_DIR_PATH."/create_user.xml",
								TRUE);
		
		if ($id === -1)
			return UsrRegStat::INTERNAL_ERROR;
		else
			return $id;
	}
	
	/*
	 * If authorization succeeded, user UID is returned.
	 */
	public static function auth($user_id, $pwd, $byName = 1) {
			if ($byName) 
				$c1 = new SqlCondition('name', SqlCondition::EQUAL, $user_id);
			else
				$c1 = new SqlCondition('uid', SqlCondition::EQUAL, $user_id);
			$condition = array();
			$condition[] = $c1;
			$c2 = new SqlCondition('password', SqlCondition::EQUAL, $pwd);
			$condition[] = $c2;
			$cl = new SqlCondList();
			$cl->add_condition($c1);
			$cl->add_relation(SqlCondition::_AND);
			$cl->add_condition($c2);
			
			$db_opera = new DatabaseOperator();
			$db_opera->config(CONFIGURATION_DIR_PATH."/user_table.xml");
			$r = $db_opera->select($cl);
				
			if ($r != NULL && (count($r) == 1))
				return $r[0]['uid'];
			else
				return FALSE;
	}
	/*
	 * $this->uid identified user is to login.
	 */
	public static function login($user_id, $password, $forced = FALSE, $byName = FALSE) {
		/*
		 * Validate information provided.
		 */
		if ($byName) {
			/* $user_id is an user name.
			 * Get user information first.
			 */
			$user_objs = UserManager::get_user_by_name($user_id);
			if ( ($user_objs === NULL) || (count($user_objs) != 1))
				return LoginStat::LOGIN_USER_NOT_FOUND;
				
			$user_obj = $user_objs[0];	
			// Overwrite the $user_id for the further processing.
			$user_id = $user_obj->uid;
		}
		
		if ($user_id === NULL)
			return LoginStat::LOGIN_UID_REQUIRED;
			
		if ($password === NULL)
			return LoginStat::LOGIN_PASSWORD_REQUIRED;
		
		$sc = new Session_Controller();
		$sc->start_session();
		
		if (isset($_SESSION["ID"])) {
			/*
			 * In an active session now. You have already logged in.
			*/
			echo "set user ID in session";
			$is_same_user = UserManager::is_the_same_user($user_id, $_SESSION["ID"]);
			if ($is_same_user)
				return LoginStat::LOGIN_NOT_NEEDED;				
		}
		
		return UserManager::__login($user_id, $password, $forced);
	}
	
	/*
	 * Check whether the UID in current session is the same with the UID to login.
	 */
	public static function is_the_same_user($uid2login, $uid_in_session) {
		if ($uid2login === $uid_in_session) {
			// Already logged in.
			return TRUE;
		} else {
			// Log out the old user. Just set it's session_id in database to NULL.
			$updated_array = array();
			$updated_array['session_id'] = NULL; // Get the current session ID and update it.
			$condition = new SqlCondition('uid', SqlCondition::EQUAL, $uid_in_session);
			$c = new SqlCondList();
			$c->add_condition($condition);	
			
			$db_opera = new DatabaseOperator();
			$db_opera->config(CONFIGURATION_DIR_PATH."/user_table.xml");	
			$db_opera->update($updated_array, $c);
			
			// Set the $_SESSION['ID'] to the UID to login.
			$_SESSION["ID"] = $uid2login; 
			return FALSE;
		}
	}
	
	public static function auth_pwd($u_uid, $pwd) {
		$db_opera = new DatabaseOperator();
		$db_opera->config(CONFIGURATION_DIR_PATH."/user_table.xml");
		$cList = new SqlCondList();
		$cList->add_condition(new SqlCondition("uid", SqlCondition::EQUAL, $u_uid));
		$cList->add_relation(SqlCondition::_AND);
		$cList->add_condition(new SqlCondition("password", SqlCondition::EQUAL, $pwd));
		$usrs = $db_opera->select($cList);
		if (count($usrs) == 0)
			return FALSE;
		else
			return TRUE;
	}
	
	/*
	 * Check whether the user name is available.
	 */
	public static function is_user_name_in_use($name) {
		$db_opera = new DatabaseOperator();
		$db_opera->config(CONFIGURATION_DIR_PATH."/user_table.xml");
		$cList = new SqlCondList();
		$cList->add_condition(new SqlCondition("name", SqlCondition::EQUAL, $name));	
		$usrs = $db_opera->select($cList);
		if (count($usrs) > 0)
			return TRUE;
		else
			return FALSE;
	}
	
	/*
	 * Actual login operation.
	 */
	public static function __login($user_id, $password, $forced) {
		// Get the current session_id in the database.
		$cols[] = "session_id";
		$cols[] = "name";
		$cols[] = "city";
		$c1 = new SqlCondition('uid', SqlCondition::EQUAL, $user_id);
		$condition = array();
		$condition[] = $c1;
		$c2 = new SqlCondition('password', SqlCondition::EQUAL, $password);
		$condition[] = $c2;
		$cl = new SqlCondList();
		$cl->add_condition($c1);
		$cl->add_relation(SqlCondition::_AND);
		$cl->add_condition($c2);
		
		$db_opera = new DatabaseOperator();
		$db_opera->config(CONFIGURATION_DIR_PATH."/user_table.xml");
		$r = $db_opera->select($cl, $cols);
		
		if (count($r) != 1) {
			return LoginStat::LOGIN_INVALID_INFORMATION;
		}
		
		$record = $r[0]; // Only one row of result should be returned.
		$sid_in_db = $record["session_id"];
		$user_name = $record["name"];
		$user_city = $record["city"];
		
		if ($sid_in_db != NULL) {
			// Already logged in elsewhere.
			if (!$forced) {
				return LoginStat::LOGIN_ELSEWHERE;
			} else {
				// Delete the old session file.
				$sess_file = SESSION_FILES_DIR_PATH."sess_$sid_in_db";
				@unlink($sess_file);
			}
		}
		
		// Bind user information in the session.
		$_SESSION["ID"] 		= $user_id;
		$_SESSION["USERNAME"] 	= $user_name;
		$_SESSION["CITY"]		= $user_city;
				
		$updated_array = array();
		$updated_array['session_id'] = session_id();
		$condition = new SqlCondition('uid', SqlCondition::EQUAL, $user_id);
		$c = new SqlCondList();
		$c->add_condition($condition);		
		$db_opera->update($updated_array, $c);
		
		return LoginStat::LOGIN_OK;
	}
	
	public static function logout(/*$user_uid*/) {
		$sc = new Session_Controller();
		$sc->start_session();
		
		if (!isset($_SESSION["ID"]))
			return LogoutStat::LOGOUT_NOT_NEEDED;
		
		$user_uid = $_SESSION["ID"];
		
		$sc->destroy_session();
		
		/*
		 * Check the session_id. If it is set to NULL, logout operation succeeded.
		 */
		$cols[] = "session_id";
		$c1 = new SqlCondition('uid', SqlCondition::EQUAL, $user_uid);
		$condition = array();
		$condition[] = $c1;
		$cl = new SqlCondList();
		$cl->add_condition($c1);
		
		$db_opera = new DatabaseOperator();
		$db_opera->config(CONFIGURATION_DIR_PATH."/user_table.xml");
		$r = $db_opera->select($cl, $cols);
		
		if (count($r) != 1) {
			return LogoutStat::LOGOUT_INVALID_INFORMATION;
		}
		
		$record = $r[0]; // Only one row of result should be returned.
		$sid_in_db = $record["session_id"];
		
		if ($sid_in_db != NULL) {
			// Already logged in elsewhere.
			return LogoutStat::LOGOUT_FAILED;
		} else {
			return LogoutStat::LOGOUT_OK;
		}
	}
	
	/*
	 * 1. Create a such UserManager object. Set the parameters to be updated.
	 * 2. uid is used to identify the user to be updated.
	 * 3. Invoke the update_info function to update the information.
	 */
	public function update_info() {
		$operator = new DatabaseOperator();
		$operator->config(CONFIGURATION_DIR_PATH."/user_table.xml");
		
		$info = $this->toArray();
		
		if (count($info)) {
			$condList = new SqlCondList();
			$condList->add_condition(new SqlCondition('uid', SqlCondition::EQUAL, $this->uid));
			$stat = $operator->update($info, $condList);
			if(!DbError::is_error($stat)) {
				return TRUE;
			} else {
				return FALSE;
			}
		} else {
			return TRUE;
		}
	}
	
	/*
	 * Get the invite requests list.
	 * 
	 * Parameter:
	 * $member_uid: the uid of the invited member.
	 * 
	 * Return value:
	 * An array containing all the teams request to invite the member. This array is indexed by integer.
	 */
	public static function get_invite_request($member_uid) {
		$operator = new DatabaseOperator();
		$operator->config(CONFIGURATION_DIR_PATH."/member_invite_request_table.xml");
		
		$condList = new SqlCondList();
		$condList->add_condition(new SqlCondition('invited_member_id', SqlCondition::EQUAL, $member_uid));
		$cols[] = "invite_team_uid";
		$ret = $operator->select($condList, $cols);
		return $ret;	
	}
	
	/* 
	 * 1. Update the invite request's status to accepted/rejected.
	 * 2. If accepted, update the user's team to the team identified by $team_uid.
	 * 
	 * Parameter:
	 * $user_uid: the player's uid who is invited.
	 * $team_uid: the team which sends to invite request.
	 * 
	 * Return value: TRUE if operation succeeds; otherwise FALSE.
	 */
	public static function reply_invite_request($user_uid, $team_uid, $accepted) {
		$status = array();
		if ($accepted)
			$status["status"] = MemberInviteRequestStat::REQ_ACCEPTED;
		else
			$status["status"] = MemberInviteRequestStat::REQ_REJECTED;
		
		// 1.
		$opera = new DatabaseOperator();
		$opera->config(CONFIGURATION_DIR_PATH."/member_invite_request_table.xml");
		$condList = new SqlCondList();
		$condList->add_condition(new SqlCondition('invited_member_uid', SqlCondition::EQUAL, $user_uid));
		$condList->add_relation(SqlCondition::_AND);
		$condList->add_condition(new SqlCondition('invite_team_uid', SqlCondition::EQUAL, $team_uid));
		$stat = $opera->update($status, $condList);
		
		if(DbError::is_error($stat))
			return FALSE;
		
		// 2.
		if($accepted) {
			$opera->config(CONFIGURATION_DIR_PATH."/team_member_table.xml");
			$new_team["teamid"] = $team_uid;
			$condList = new SqlCondList();
			$condList->add_condition(new SqlCondition('memberid', SqlCondition::EQUAL, $user_uid));
			$stat = $opera->update($new_team, $condList);
			return DbError::is_error($stat);
		} else {
			return TRUE;
		}
	}
	
	public function query_by_uids($uid) {
		/*
		 * Query information by the UID specified by $uid.
		 */
		$rows = parent::query_by_uids(CONFIGURATION_DIR_PATH."/user_table.xml", $uid);
		
		if ($rows === NULL) {
			return NULL;
		} else {
			$ret = array();
			$user_delegate = new User();
			foreach ($rows as $row) {
				$tmp = $user_delegate->array2copy($row);
				$ret[] = $tmp;
			}
			return $ret;
		}
	}
	
	/*
	 * List current user list.
	 */
	public static function query_user_list($condition_list) {
		$op = new DatabaseOperator();
		$op->config(CONFIGURATION_DIR_PATH."/user_table.xml");
		$ret_array = $op->select($condition_list);
		
		$return_val = array();
		$user_obj = new User();
		foreach ($ret_array as $item) {
			$return_val[] = $user_obj->array2copy($item);
		}
		
		return $return_val;
	}
	
	/*
	 * Parameter:
	 * $names: an array of user names;
	 * 
	 * Return value:
	 * User objects if the user with name $name is found; otherwise NULL is returned.
	 */
	public static function get_user_by_name($names) {
		if ($names === NULL)
			return NULL;
		
		$op = new DatabaseOperator();
		$op->config(CONFIGURATION_DIR_PATH."/user_table.xml");
		$condition_list = new SqlCondList();
		
		if (gettype($names) != gettype(array()))
			$condition_list->add_condition(new SqlCondition("name", SqlCondition::EQUAL, $names));
		else {
			$cnt = count($names);
			$i = 0;
			for (; $i < $cnt - 1; ++$i) {
				$condition_list->add_condition(new SqlCondition("name", SqlCondition::EQUAL, $names[$i]));
				$condition_list->add_condition(SqlCondition::_OR);
			}
			$condition_list->add_condition(new SqlCondition("name", SqlCondition::EQUAL, $names[$cnt - 1]));
		}
		
		$ret_array = $op->select($condition_list);
		
		$return_val = array();
		$user_obj = new User();
		foreach ($ret_array as $item) {
			$return_val[] = $user_obj->array2copy($item);
		}
		
		return $return_val;
	}
	
	/*
	 * Parameter:
	 * $names: an array of user names;
	 * 
	 * Return value:
	 * User UIDs if the user with name $name is found; otherwise NULL is returned.
	 * An array: key->uid, value->name.
	 */
	public static function get_user_uids_by_name($names) {
		if ($names === NULL)
			return NULL;
		
		$op = new DatabaseOperator();
		$op->config(CONFIGURATION_DIR_PATH."/user_table.xml");
		$condition_list = new SqlCondList();
		
		if (gettype($names) != gettype(array()))
			$condition_list->add_condition(new SqlCondition("name", SqlCondition::EQUAL, $names));
		else {
			$cnt = count($names);
			$i = 0;
			for (; $i < $cnt - 1; ++$i) {
				$condition_list->add_condition(new SqlCondition("name", SqlCondition::EQUAL, $names[$i]));
				$condition_list->add_relation(SqlCondition::_OR);
			}
			$condition_list->add_condition(new SqlCondition("name", SqlCondition::EQUAL, $names[$cnt - 1]));
		}
		
		$target[] = "uid";
		$target[] = "name";
		$ret_array = $op->select($condition_list, $target);
		$return_val = array();
		$user_obj = new User();
		foreach ($ret_array as $item) {
			$return_val[$item["uid"]] = $item["name"];
		}
		
		return $return_val;
	}
	
	/*
	 * Parameter:
	 * $by :0 - By registered time
	 * 		1 - By goals
	 */
	public static function getTop($top, $by = 1) {
		$opera = new DatabaseOperator();
		//$user_config = new SqlAlias(CONFIGURATION_DIR_PATH."/user_table.xml", "a");
		//$cfg[] = $user_config;
		$opera->config(CONFIGURATION_DIR_PATH."/user_table.xml");
		//$opera->config($cfg);
		$cList = new SqlCondList();
		if ($by == 1)
			$cList->add_constraint(new SqlConstraint(SqlConstraint::ORDERBY, "goal"));
		else if ($by == 0)
			$cList->add_constraint(new SqlConstraint(SqlConstraint::ORDERBY, "regdate"));
		else
			$cList->add_constraint(new SqlConstraint(SqlConstraint::ORDERBY, "uid"));
		
		$cList->add_sort(new SqlSort(SqlSort::DESC));
		$cList->add_limit(new SqlLimit(0, $top));
		
		$rows = $opera->select($cList);
		$ret = array();
		
		$user_delegate = new User();
		if ($rows != null && count($rows) > 0) {
			foreach ($rows as $row) {
				$tmp = $user_delegate->array2copy($row);
				$ret[] = $tmp;
			}
		}
		
		return $ret;
	}
	
	/*
	 * Get the invite requests list.
	 * 
	 * Parameter:
	 * $member_uid: the uid of the invited member.
	 * 
	 * Return value:
	 * An array containing all the teams request to invite the member. This array is indexed by integer.
	 */
	public static function GetIconByUID($uid) {
		$operator = new DatabaseOperator();
		$operator->config(CONFIGURATION_DIR_PATH."/user_table.xml");
		
		$condList = new SqlCondList();
		$condList->add_condition(new SqlCondition('uid', SqlCondition::EQUAL, $uid));
		$cols[] = "icon_file";
		$ret = $operator->select($condList, $cols);
		if (count($ret) == 1)
			return $ret[0]["icon_file"];
		else
			return null;
	}
}
?>